//============================================================================//
// [ MousePoint ]                                                      [樹招] //
//============================================================================//

// Ver.0.04 (2007/04/07)

//----------------------------------------------------------------------------//
// SetMouseClick id x y w h key [subroutine [p1 p2 p3...]]
//  -> マウスクリックポイントを設定する。
//------------------------------------//
SetMouseClick:
	Local data_cnt = Count(MP_ClickPoint) + 1
	Local data_id = IIf(Args(1) != "", Args(1), "NO_ID")
	Local data = MP_SetEventData(7)
	
	// 基点の座標を設定する
	Local pos_x = BaseX + Args(2)
	Local pos_y = BaseY + Args(3)
	
	// 対象キー番号を設定する
	Local key = 1
	Switch LCase(Args(6))
	Case "left"
		key = 1
	Case "right"
		key = 2
	Case "wheel" "middle"
		key = 4
	Case "both"
		key = "1 2"
	Case "all"
		key = "1 2 4"
	EndSw
	
	// ClickPointを登録する
	Set MP_ClickPoint[data_cnt] List("(" & data_id & ")", "(" & key & ")",_
		pos_x, pos_y, pos_x + Args(4), pos_y + Args(5), "(" & data & ")")
	// IDを登録する
	Call MP_SetEventID "Click" data_id data_cnt
Return


//----------------------------------------------------------------------------//
// SetMouseOver [id x y w h] subroutine [p1 p2 p3...]
//  -> マウスオーバーポイントを設定する。
//------------------------------------//
SetMouseOver:
	Local data_cnt = Count(MP_OverPoint) + 1
	
	// 設定情報を取得する
	If (LCase(Args(1)) = "_copy") Then
		If Count(MP_ClickPoint) = 0 Then
			Return  // ClickPointが存在しなければ終了する
		EndIf
		
		// ClickPointから情報を取得する
		Local copy_data = MP_ClickPoint[Count(MP_ClickPoint)]
		Local data_id = LIndex(copy_data, 1)
		Local data = MP_SetEventData(2)
		Local pos_data = List(LIndex(copy_data, 3), LIndex(copy_data, 4),_
			LIndex(copy_data, 5), LIndex(copy_data, 6))
	Else
		Local data_id = IIf(Args(1) != "", Args(1), "NO_ID")
		Local data = MP_SetEventData(6)
		Local pos_x = BaseX + Args(2)
		Local pos_y = BaseY + Args(3)
		Local pos_data = List(pos_x, pos_y, pos_x + Args(4), pos_y + Args(5))
	EndIf
	
	// OverPointを登録する
	Set MP_OverPoint[data_cnt] List("(" & data_id & ")", pos_data, "(" & data & ")")
	// IDを登録する
	Call MP_SetEventID "Over" data_id data_cnt
Return


//----------------------------------------------------------------------------//
// ClearMousePoint [option] or ClearMousePoint [type (id or number)]
//  -> MousePointを初期化する。 or 特定のPointを削除する。
//------------------------------------//
ClearMP:
ClearMousePoint:
	Switch LCase(Args(1))
	Case "click"
		// ClickPointを削除する
		Call ClearMP_Point "Click"
	Case "over"
		// OverPointを削除する
		Call ClearMP_Point "Over"
	Case "point"
		// ClickPoint,OverPointを削除する
		Call ClearMP_Point "Click"
		Call ClearMP_Point "Over"
	Case "reserve"
		// Pointを一時的に別配列に保存する
		Call ClearMP_Reserve
		Call ClearMP_Info Args(2)
	Case "restore"
		// 保存したPointを復元する
		Call ClearMP_Restore
		Call ClearMP_Info Args(2)
	Case Else
		// MousePointの変数を全て破棄する
		Call ClearMP_Point
		Call ClearMP_Stack
		Call ClearMP_Info Args(1)
	EndSw
Return


//-- ClearMP_Point type [(id or number)] : 指定したPointを削除する --//
ClearMP_Point:
	Local type = Args(1)
	Local array1 = "MP_" & type & "Point"
	Local array2 = "MP_" & type & "PointID"
	Local array_cnt = Eval("Count(" & array1 & ")")
	
	If ArgNum = 0 Then
		// 引数が0の場合はPointを全て削除して終了する
		UnSet MP_ClickPoint
		UnSet MP_ClickPointID
		UnSet MP_OverPoint
		UnSet MP_OverPointID
		Return
	ElseIf array_cnt = 0 Then
		// イベントデータが存在しない場合は終了する
		Return
	EndIf
	
	UpVar
	
	// 引数2が空文字列の場合は該当のPointを削除して終了する
	If (ArgNum = 2) Or (array_cnt = 0) Then
		UnSet Eval(array1)
		UnSet Eval(array2)
		Return
	EndIf
	
	// 削除対象の番号を設定する
	Local remove_num i
	For i = 3 To ArgNum
		If IsNumeric(Args(i)) Then
			remove_num = remove_num & " " & Args(i)
		ElseIf Eval("IsVarDefined(" & array2 & "[Args(i)])") Then
			remove_num = remove_num & " " & Eval(array2 & "[Args(i)]")
		EndIf
	Next
	remove_num = Trim(remove_num)
	
	If remove_num = "" Then
		Return  // 削除対象が設定されない場合は終了する
	ElseIf LLength(remove_num) = array_cnt Then
		// 削除数とイベント数が同じなら変数を削除して終了する
		UnSet Eval(array1)
		UnSet Eval(array2)
		Return
	EndIf
	
	// イベントリストを一時的に退避させる
	CopyArray Eval(array1) MP_Temporary
	UnSet Eval(array1)
	UnSet Eval(array2)
	
	// 削除対象以外を再設定する
	Local idx = 1
	For i = 1 To array_cnt
		If LSearch(remove_num, i) = 0 Then
			Eval(array1 & "[idx]") = MP_Temporary[i]
			Call MP_SetEventID type LIndex(MP_Temporary[i], 1) idx
			Incr idx 1
		EndIf
	Next
	
	// 不必要になった変数を削除する
	UnSet MP_Temporary
Return


//-- ClearMP_Reserve : Pointを一時的に別配列に保存する --//
ClearMP_Reserve:
	If (Count(MP_ClickPoint) + Count(MP_OverPoint)) = 0 Then
		Return  // Pointが設定されていない場合は終了する
	EndIf
	
	// 保存数を記録する
	Incr MP_StackCount 1
	
	// Pointを保存する
	CopyArray MP_ClickPoint Eval("MP_ClickPoint_Stack" & MP_StackCount)
	CopyArray MP_ClickPointID Eval("MP_ClickPointID_Stack" & MP_StackCount)
	CopyArray MP_OverPoint Eval("MP_OverPoint_Stack" & MP_StackCount)
	CopyArray MP_OverPointID Eval("MP_OverPointID_Stack" & MP_StackCount)
	
	// Pointを初期化する
	Call ClearMP_Point
Return


//-- ClearMP_Restore : 保存したPointを復元する --//
ClearMP_Restore:
	// Pointを初期化する
	Call ClearMP_Point
	
	If Not IsVarDefined(MP_StackCount) Then
		Return  // 保存したPointが0の場合は終了する
	EndIf
	
	// Pointを復元する
	CopyArray Eval("MP_ClickPoint_Stack" & MP_StackCount) MP_ClickPoint
	CopyArray Eval("MP_ClickPointID_Stack" & MP_StackCount) MP_ClickPointID
	CopyArray Eval("MP_OverPoint_Stack" & MP_StackCount) MP_OverPoint
	CopyArray Eval("MP_OverPointID_Stack" & MP_StackCount) MP_OverPointID
	UnSet Eval("MP_ClickPoint_Stack" & MP_StackCount)
	UnSet Eval("MP_ClickPointID_Stack" & MP_StackCount)
	UnSet Eval("MP_OverPoint_Stack" & MP_StackCount)
	UnSet Eval("MP_OverPointID_Stack" & MP_StackCount)
	
	// StackCountが1なら変数を削除する
	If MP_StackCount = 1 Then
		UnSet MP_StackCount
	Else
		Incr MP_StackCount -1
	EndIf
Return


//-- ClearMP_Stack : 保存情報を破棄する --//
ClearMP_Stack:
	If Not IsVarDefined(MP_StackCount) Then
		Return  // 保存したPointが0の場合は終了する
	EndIf
	
	Local i
	For i = 1 To MP_StackCount
		UnSet Eval("MP_ClickPoint_Stack" & i)
		UnSet Eval("MP_ClickPointID_Stack" & i)
		UnSet Eval("MP_OverPoint_Stack" & i)
		UnSet Eval("MP_OverPointID_Stack" & i)
	Next
Return


//-- ClearMP_Info [option] : 情報変数の破棄する --//
ClearMP_Info:
	If LCase(Args(1)) != "keep" Then
		UnSet MP_Select
	EndIf
	UnSet MP_MouseXY
	UnSet MP_NowClickID
	UnSet MP_NowOverID
Return


//----------------------------------------------------------------------------//
// WaitMousePoint [var_name]
//  -> "Wait Click"の代わり。使い分けが面倒な人用。
//------------------------------------//
WaitMousePoint:
	Local var_name = IIf(Args(1) != "", Args(1), "MP_Select")
	
	// 選択結果を初期化する
	Eval(var_name) = ""
	
	// 選択結果が格納されるまでループする
	Do While (Eval(var_name) = "")
		Wait 0.15
		Call ProcessMouseOver var_name
		Call ProcessMouseClick
	Loop
Return


//----------------------------------------------------------------------------//
// ProcessMouseClick [var_name]
//  -> 設定されたマウスクリックのイベントの処理を行う。
//------------------------------------//
ProcessMouseClick:
	If (Not IsVarDefined(MP_ClickPoint)) Or (Not (KeyState(1) Or KeyState(2) Or KeyState(4))) Then
		Return  // ClickPointが存在しない、クリックされていない場合は終了する
	EndIf
	
	Local var_name = IIf(Args(1) != "", Args(1), "MP_Select")
	Local event data i
	
	// 範囲内にカーソルが存在するClickPointを検索する
	For i = 1 To Count(MP_ClickPoint)
		data = MP_ClickPoint[i]
		If Not MP_KeyListState(LIndex(data, 2)) Then
			Skip  // 対象キーがおされていない場合はスキップする
		ElseIf Not MP_IsMouseOver(LIndex(data, 3), LIndex(data, 4), LIndex(data, 5), LIndex(data, 6)) Then
			Skip  // 範囲内にカーソルが存在しない場合はスキップする
		EndIf
		
		// イベント番号と選択結果を変数に記録する
		Set MP_NowClickID i
		Eval(var_name) = LIndex(data, 1)
		
		// イベントサブルーチンが設定されている場合は呼び出す
		If LIndex(data, 7) != "" Then
			event = Eval(LIndex(data, 7))
		EndIf
		
		Return
	Next
	
	// 左クリック、ホイールクリックが解除されるまで待機する
	Do While (KeyState(1) Or KeyState(4))
		Wait 0.15
	Loop
Return


//----------------------------------------------------------------------------//
// ProcessMouseOver
//  -> 設定されたマウスオーバーのイベントの処理を行う。
//------------------------------------//
ProcessMouseOver:
	If (Not IsVarDefined(MP_OverPoint)) Or (MP_MouseXY = List(MouseX, MouseY)) Then
		Return  // OverPointが存在しない、カーソルが動いていない場合は終了する
	EndIf
	
	// カーソルの位置を記録する
	Set MP_MouseXY List(MouseX, MouseY)
	
	Local display = ""  // 画面更新のフラグを設定する
	Local data
	
	// 実行中のイベントをチェックする
	If IsVarDefined(MP_NowOverID) Then
		data = MP_OverPoint[MP_NowOverID]
		// 範囲内にカーソルがない場合はサブルーチンを呼び出す
		If Not MP_IsMouseOver(LIndex(data, 2), LIndex(data, 3), LIndex(data, 4), LIndex(data, 5)) Then
			UnSet MP_NowOverID
			display = Eval(LIndex(data, 6))
		Else
			Return  // カーソルが範囲内なら終了する
		EndIf
	EndIf
	
	// 範囲内にカーソルが存在するOverPointを検索する
	Local i
	For i = 1 To Count(MP_OverPoint)
		data = MP_OverPoint[i]
		If Not MP_IsMouseOver(LIndex(data, 2), LIndex(data, 3), LIndex(data, 4), LIndex(data, 5)) Then
			Skip  // 範囲内にカーソルが存在しない場合はスキップする
		EndIf
		
		// 範囲内にカーソルが存在するイベントを実行する
		Set MP_NowOverID i
		display = Eval(LIndex(data, 6))
		Break
	Next
	
	// イベントの返り値に"keep"が指定されていない場合は画面を更新する
	If LCase(display) != "keep" Then
		Refresh  // ちらつき防止
	EndIf
Return


//----------------------------------------------------------------------------//
// MousePoint Function
//----------------------------------------------------------------------------//

//-- SetEventID type id number : イベントIDを登録する --//
MP_SetEventID:
	Local array1 = "MP_" & Args(1) & "PointID[" & Args(2) & "]"
	
	// IDを登録する
	Eval(array1) = Trim(Eval(array1) & " " & Args(3))
	
	// リスト式のIDはリストの一番目もIDとして登録する
	If LLength(Args(2)) > 1 Then
		Local array2 = "MP_" & Args(1) & "PointID[" & LIndex(Args(2), 1) & "]"
		Eval(array2) = Trim(Eval(array2) & " " & Args(3))
	EndIf
Return


//-- SetEventData(start_idx) : サブルーチン名とその引数を関数の形にして返す --//
MP_SetEventData:
	UpVar
	
	Local start_idx = Args(1) + 1
	Local name = Args(start_idx)
	Local data i
	
	If name = "" Then
		Return ""  // サブルーチン名がなければ空文字列を返す
	EndIf
	
	// 引数を連結する
	For i = (start_idx + 1) To ArgNum
		data = data & ",`" & Args(i) & "`"
	Next
Return (name & "(" & Mid(data, 2) & ")")


//-- GetEventData type (id or number) : 設定されたサブルーチンのパラメータをリストで返す --//
MP_GetEventData:
	Local array1 = "MP_" & Args(1) & "Point[num]"
	Local array2 = "MP_" & Args(1) & "PointID[num]"
	Local num = Args(2)
	
	// IDから番号を取得する
	If Not IsNumeric(num) Then
		If Eval("IsVarDefined(" & array2 & ")") Then
			num = LIndex(Eval(array2), Max(Args(3), 1))
		Else
			Return ""
		EndIf
	EndIf
	
	If Eval("IsVarDefined(" & array1 & ")") Then
		Local data = LIndex(Eval(array1), 6 + (Args(1) = "Click"))
		Return Eval("List(" & RegExpReplace(data, "[^\(]*\((.*)\)", "$1") & ")")
	EndIf
Return ""


//-- UpdateEventData type (id or number) subroutine p1 p2 p3... : 設定されたサブルーチンのデータを更新する --//
MP_UpdateEventData:
	Local array1 = "MP_" & Args(1) & "Point[num]"
	Local array2 = "MP_" & Args(1) & "PointID[num]"
	Local num = Args(2)
	
	// IDから番号を取得する
	If Not IsNumeric(num) Then
		If Eval("IsVarDefined(" & array2 & ")") Then
			num = LIndex(Eval(array2), 1)
		Else
			Return
		EndIf
	EndIf
	
	Local subroutine = LIndex(Eval(array1), 6 + (Args(1) = "Click"))
	Local data = Left(Eval(array1), Len(Eval(array1)) - Len(subroutine) - 2)
	Local event_data = MP_SetEventData(3)
	
	Eval(array1) = data & "(" & event_data & ")"
Return


//-- IsMouseOver(x1, y1, x2, y2) : 指定した範囲内にマウスカーソルがあれば[1]を返す --//
MP_IsMouseOver:
	If (MouseX >= Args(1)) And (MouseY >= Args(2)) _
			And (MouseX < Args(3)) And (MouseY < Args(4)) Then
		Return 1
	EndIf
Return 0


//-- KeyListState(key_list) : 指定されたKeyのいずれかが押されているなら[1]を返す --//
MP_KeyListState:
	Local key = Args(1)
	Local i
	For i = 1 To LLength(key)
		If KeyState(LIndex(key, i)) Then
			Return 1
		EndIf
	Next
Return 0


//-- DummyEvent : ダミーイベント --//
MP_DummyEvent:
	// 実行したくないが、イベントを設定しておきたい場合に指定する。
Return


//-- PointDisplay [option option] : 設定されたPointの範囲を視覚的に表示する --//
MP_PointDisplay:
	Local base_pos = List(BaseX, BaseY)
	Local text x1 x2 y1 y2 i
	
	Incr BaseX (BaseX * -1)
	Incr BaseY (BaseY * -1)
	
	Font 8pt ゴシック Regular
	
	// ClickPoint
	If LCase(Args(1)) != "off" Then
		Font #ffffff
		For i = 1 To Count(MP_ClickPoint)
			text = "C" & i
			x1 = LIndex(MP_ClickPoint[i], 3)
			y1 = LIndex(MP_ClickPoint[i], 4)
			x2 = LIndex(MP_ClickPoint[i], 5) - 1
			y2 = LIndex(MP_ClickPoint[i], 6) - 1
			Line x1 y1 x2 y2 B #ffffff
			PaintString (x1 + 3) (y1 + 3) text
		Next
	EndIf
	
	// OverPoint
	If LCase(Args(2)) != "off" Then
		Font #ff0000
		For i = 1 To Count(MP_OverPoint)
			text = "Ov" & i
			x1 = LIndex(MP_OverPoint[i], 2)
			y1 = LIndex(MP_OverPoint[i], 3)
			x2 = LIndex(MP_OverPoint[i], 4) - 1
			y2 = LIndex(MP_OverPoint[i], 5) - 1
			Line x1 y1 x2 y2 B #ff0000
			PaintString (x2 - TextWidth(text)) (y2 - TextHeight(text)) text
		Next
	EndIf
	
	BaseX = LIndex(base_pos, 1)
	BaseY = LIndex(base_pos, 2)
Return


